﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TCP_IP_Spike
{
    public class TcpEngine
    {
        public Queue TxQueue { get; set; }
        public Queue RxQueue { get; set; }

        private readonly TcpListener _listener;

        public TcpEngine()
        {
            TxQueue = Queue.Synchronized(new Queue());
            RxQueue = Queue.Synchronized(new Queue());
            _listener = new TcpListener(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9059));
        }

        public TcpEngine(string ip, int port)
        {
            TxQueue = Queue.Synchronized(new Queue());
            RxQueue = Queue.Synchronized(new Queue());
            _listener = new TcpListener(new IPEndPoint(IPAddress.Parse(ip), port));
        }

        public void TcpServerThread()
        {
            _listener.Start();
            Console.WriteLine("Starting TCP server , listening on: " + _listener.Server.LocalEndPoint);
            while (true)
            {
                //if there is an incoming connection, start a thread to receive it
                while (_listener.Pending())
                    new Thread(_rxThread).Start();

                //if there is a message to be sent, create a thread to send it
                while (TxQueue.Count > 0)
                    new Thread(new TcpTxObject(TxQueue.Dequeue().ToString()).TxThread).Start();

                Thread.Sleep(250);
            }
        }

        private void _rxThread()
        {
            var bytes = new byte[256];

            var client = _listener.AcceptTcpClient();

            Console.WriteLine("Receiving TCP message from: " + client.Client.RemoteEndPoint);

            var stream = client.GetStream();

            int i;
            while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
            {
                //var data = ;
                RxQueue.Enqueue("[" + client.Client.RemoteEndPoint + "]" + Encoding.ASCII.GetString(bytes, 0, i));
            }

            client.Close();
        }
    }

    public class TcpTxObject
    {
        private readonly IPEndPoint _ipEndPoint;// { get; set; }
        private readonly byte[] _msg;//{ get; set; }

        public TcpTxObject(string txString)
        {
            var txMsg = txString.Split('@');
            var ip = IPAddress.Parse(txMsg[0]);
            _ipEndPoint = new IPEndPoint(ip, Convert.ToInt16(txMsg[1]));
            _msg = Encoding.ASCII.GetBytes(txMsg[2]);
        }

        public void TxThread()
        {
            Console.WriteLine("Sending a message to " + _ipEndPoint);
            var client = new TcpClient();
            client.Connect(_ipEndPoint);
            var stream = client.GetStream();
            stream.Write(_msg, 0, _msg.Length);
            client.Close();
        }
    }
}
